<!DOCTYPE html>
<script src="../resources/js-test.js"></script>
<script>
description('IDL union types unittests');

var element = document.createElement('div');
var nodeList = document.querySelectorAll('script');

if (window.internals) {
    // The conversion rule prefers string over double, hence a value which
    // is neither double nor string will be converted using ToString().

    var unionTypesTest = internals.unionTypesTest();

    debug('Tests for attributes');
    shouldBe('unionTypesTest.doubleOrStringOrStringSequenceAttribute', '0');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = 3.14;
    shouldBe('unionTypesTest.doubleOrStringOrStringSequenceAttribute', '3.14');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = "foo";
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceAttribute', 'foo');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = undefined;
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceAttribute', 'undefined');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = null;
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceAttribute', 'null');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = {};
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceAttribute', '[object Object]');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = [];
    shouldBeEqualToString('JSON.stringify(unionTypesTest.doubleOrStringOrStringSequenceAttribute)', '[]');
    unionTypesTest.doubleOrStringOrStringSequenceAttribute = ['a', 3.14];
    shouldBeEqualToString('JSON.stringify(unionTypesTest.doubleOrStringOrStringSequenceAttribute)', '["a","3.14"]');
    debug('');

    debug('Tests for method arguments');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg(3.14)', 'double is passed: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg("foo")', 'string is passed: foo');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg(undefined)', 'string is passed: undefined');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg(null)', 'string is passed: null');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg({})', 'string is passed: [object Object]');
    shouldBeEqualToString('unionTypesTest.doubleOrStringArg([])', 'string is passed: ');
    // ToString(Date) can contain timezone, so we can't specify the expectation.
    // Just check that doubleOrStringArg() doesn't throw an exception.
    shouldBeEqualToString('typeof unionTypesTest.doubleOrStringArg(new Date)', 'string');
    shouldThrow('unionTypesTest.doubleOrStringArg()');
    debug('');

    shouldBeEqualToString('unionTypesTest.doubleOrInternalEnumArg(3.14)', 'double is passed: 3.14');
    // "foo" is a valid InternalEnum value.
    shouldBeEqualToString('unionTypesTest.doubleOrInternalEnumArg("foo")', 'InternalEnum is passed: foo');
    shouldThrow('unionTypesTest.doubleOrInternalEnumArg("invalid")');
    // Implicit string conversion will occur for non-double or non-string values
    // and they result in invalid InternalEnum values, so exceptions should be
    // thrown.
    shouldThrow('unionTypesTest.doubleOrInternalEnumArg(null)');
    shouldThrow('unionTypesTest.doubleOrInternalEnumArg({})');
    shouldThrow('unionTypesTest.doubleOrInternalEnumArg([])');
    debug('');

    shouldBeEqualToString('unionTypesTest.doubleOrStringSequenceArg([])', '');
    shouldBeEqualToString('unionTypesTest.doubleOrStringSequenceArg([3.14, "foo"])', 'double: 3.14, string: foo');
    shouldBeEqualToString('unionTypesTest.doubleOrStringSequenceArg([1, "foo", "bar", 2])', 'double: 1, string: foo, string: bar, double: 2');
    shouldBeEqualToString('unionTypesTest.doubleOrStringSequenceArg([null, undefined, {}, []])', 'string: null, string: undefined, string: [object Object], string: ');
    shouldThrow('unionTypesTest.doubleOrStringSequenceArg(null)');
    shouldThrow('unionTypesTest.doubleOrStringSequenceArg(undefined)');
    shouldThrow('unionTypesTest.doubleOrStringSequenceArg({})');
    debug('');

    debug('Tests for method arguments with defaults');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultDoubleArg()', 'double is passed: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultDoubleArg(undefined)', 'double is passed: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultDoubleArg("foo")', 'string is passed: foo');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultStringArg()', 'string is passed: foo');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultStringArg(undefined)', 'string is passed: foo');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultStringArg(3.14)', 'double is passed: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultNullArg()', 'null is passed');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultNullArg(undefined)', 'null is passed');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultNullArg(null)', 'null is passed');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultNullArg(3.14)', 'double is passed: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringDefaultNullArg("foo")', 'string is passed: foo');
    debug('');

    debug('Tests for nullable method arguments');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementOrNullArg(undefined)', 'null or undefined is passed');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementOrNullArg(null)', 'null or undefined is passed');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementOrNullArg(nodeList)', 'nodelist is passed');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementOrNullArg(element)', 'element is passed');
    shouldThrow('unionTypesTest.nodeListOrElementOrNullArg(3.14)');
    shouldThrow('unionTypesTest.nodeListOrElementOrNullArg("foo")');
    shouldThrow('unionTypesTest.nodeListOrElementOrNullArg({})');
    shouldThrow('unionTypesTest.nodeListOrElementOrNullArg([])');

    shouldThrow('unionTypesTest.nodeListOrElementArg(undefined)');
    shouldThrow('unionTypesTest.nodeListOrElementArg(null)');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementArg(nodeList)', 'nodelist is passed');
    shouldBeEqualToString('unionTypesTest.nodeListOrElementArg(element)', 'element is passed');
    debug('');

    debug('Tests for method arguments with sequence members');
    shouldThrow('unionTypesTest.doubleOrStringOrStringSequenceArg()');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg("abc")', 'string: abc');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(3.14)', 'double: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(true)', 'string: true');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(null)', 'string: null');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(undefined)', 'string: undefined');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg([])', 'sequence: []');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(["a", 3.14])', 'sequence: [a, 3.14]');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceArg(new Array(3))', 'sequence: [undefined, undefined, undefined]');
    debug('');

    debug('Tests for nullable method arguments with sequence members');
    shouldThrow('unionTypesTest.doubleOrStringOrStringSequenceNullableArg()');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg("abc")', 'string: abc');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(3.14)', 'double: 3.14');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(true)', 'string: true');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(null)', 'null');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(undefined)', 'null');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg([])', 'sequence: []');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(["a", 3.14])', 'sequence: [a, 3.14]');
    shouldBeEqualToString('unionTypesTest.doubleOrStringOrStringSequenceNullableArg(new Array(3))', 'sequence: [undefined, undefined, undefined]');
}
</script>
